

TTY.ROWS	EQU	25
TTY.COLUMNS	EQU	80
TTY.TAB_LENGTH	EQU	8
TTY.SCREEN_BUFFER	EQU	0B8000h

TTY.currentRow		db	0
TTY.currentColumn	db	0

; bool TTY.printString(char* str, UINT8 row, UINT8 column,
;			char endChar, UINT8 color)
TTY.printString:
	push	ebp
	mov	ebp,	esp
; stack: |ebp |ret |str |row|col|endChar|color|
LABEL	.str	AT	ebp+4*2
LABEL	.row	AT	ebp+4*3
LABEL	.col	AT	ebp+4*3+1
LABEL	.endC	AT	ebp+4*3+2
LABEL	.color	AT	ebp+4*3+3
	push	esi
	push	edi
	
	mov	esi,	[.str]
	test	esi,	esi
	jz	.false
	
	movzx	eax,	BYTE [.row]
	movzx	edx,	BYTE [.col]
	cmp	al,	TTY.ROWS
	jae	.false
	cmp	dl,	TTY.COLUMNS
	jae	.false
	mov	[TTY.currentRow],	al
	mov	[TTY.currentColumn],	dl
	
	lea	eax,	[eax+4*eax]	; eax *= 5
	shl	eax,	5		; eax *= 16 * 2
	lea	edi,	[eax+2*edx+TTY.SCREEN_BUFFER]
	mov	ah,	[.color]
.loop0:
	lodsb
	cmp	al,	[.endC]
	je	.true
.checkBackspace:
	cmp	al,	8	; backspace '\b'
	jb	.false
	jne	.checkTab
	
	cmp	BYTE [TTY.currentColumn],	0
	jne	.else0
	cmp	BYTE [TTY.currentRow],	0
	je	.false
	dec	BYTE [TTY.currentRow]
	mov	BYTE [TTY.currentColumn],	TTY.COLUMNS - 1
	jmp	.endif0
.else0:
	dec	BYTE [TTY.currentColumn]
.endif0:
	sub	edi,	2
	jmp	.loop0

.checkTab:
	cmp	al,	9
	jne	.checkCarriage
	
	mov	dl,	[TTY.currentColumn]
	and	dl,	TTY.TAB_LENGTH - 1
	mov	dh,	TTY.TAB_LENGTH
	sub	dh,	dl
	mov	dl,	[TTY.currentColumn]
	add	dl,	dh
	cmp	dl,	TTY.COLUMNS
	jb	.else1
	mov	dl,	[TTY.currentRow]
	inc	dl
	cmp	dl,	TTY.ROWS
	jae	.false
	mov	BYTE [TTY.currentColumn],	0
	inc	BYTE [TTY.currentRow]
	jmp	.endif1
.else1:
	mov	[TTY.currentColumn],	dl
.endif1:
	mov	al,	' '
.loop1:
	stosw
	dec	dh
	jnz	.loop1
	jmp	.loop0
	
.checkCarriage:
	cmp	al,	10
	jne	.checkLineFeed
	movzx	edx,	BYTE [TTY.currentColumn]
	shl	edx,	1
	sub	edi,	edx
	mov	BYTE [TTY.currentColumn],	0
	jmp	.loop0
	
.checkLineFeed:
	cmp	al,	13
	jne	.otherChar
	mov	dl,	[TTY.currentRow]
	inc	dl
	cmp	dl,	TTY.ROWS
	jae	.false
	inc	BYTE [TTY.currentRow]
	add	edi,	TTY.COLUMNS * 2
	jmp	.loop0
	
.otherChar:
	mov	dl,	[TTY.currentColumn]
	inc	dl
	cmp	dl,	TTY.COLUMNS
	jb	.else2
	mov	dh,	[TTY.currentRow]
	inc	dh
	cmp	dh,	TTY.ROWS
	jae	.false
	inc	BYTE [TTY.currentRow]
	mov	BYTE [TTY.currentColumn],	0
	jmp	.endif2
.else2:
	inc	BYTE [TTY.currentColumn]
.endif2:
	stosw
	jmp	.loop0
	
.false:
	xor	eax,	eax
	jmp	.return
.true:
	mov	eax,	1
.return:
	pop	edi
	pop	esi
	mov	esp,	ebp
	pop	ebp
	retn	8
